#include "Common.hpp"
#include "User.hpp"
#include "ThreadPool.hpp"
using namespace MyThreadPoolMudule;
#include <cstring>

class udp_server
{
public:
    using route_t = std::function<void(int,const string&)>;
    using adduser_t = std::function<void(const User&)>;
    using delete_t = std::function<void(const User&)>;
    using task_t = std::function<void()>;
    udp_server(uint16_t port = 8080)
        :_port(port)
    {

    }
    void Init(){
        _fd = socket(AF_INET,SOCK_DGRAM,0);
        if (_fd < 0){
            LOG(ERROR) << "socket create error";
            exit(-1);
        }
        uint16_t port = ::htons(_port);
        //bind操作
        InetAddr local(port);
        if(::bind(_fd,local.Addr(),local.Len()) < 0){
            LOG(ERROR) << "bind error";
            exit(-1);
        }
    }
    void Register(route_t route,delete_t del,adduser_t add){
        _route = route;
        _del = del;
        _add = add;
    }
    void Start(){
        char buffer[1024];
        while(true){
            sockaddr_in peer;
            socklen_t Len = sizeof(peer);
            ssize_t n = ::recvfrom(_fd,buffer,1024,0,CONV(&peer),&Len);
            if (n > 0){
                InetAddr Peer(peer);
                LOG(DEBUG) << "接受到了一个连接" << Peer.NetAddr();
                if (!_userset.count(Peer.NetAddr())){
                    LOG(DEBUG) << "开始添加用户: " << Peer.NetAddr();
                    ThreadPool<task_t>::GetInstance()->Enque([=](){
                        _add(User(Peer));
                    });
                    _userset[Peer.NetAddr()] = 1;
                }
                buffer[n] = 0;
                LOG(DEBUG) << "buffer: " << buffer;
                if(strcmp(buffer,"QUIT") == 0){
                    LOG(DEBUG) << "开始删除用户: " << Peer.NetAddr();
                    ThreadPool<task_t>::GetInstance()->Enque([=](){
                        _del(User(Peer));
                    });
                    continue;   
                } 
                string client = "say# ";
                client += buffer;
                string messages = Peer.NetAddr() + client;
                //看见前面的string client了吗? 临时的, 所以我们要值拷贝
                task_t t = [=](){
                    _route(_fd,messages);
                };
                ThreadPool<task_t>::GetInstance()->Enque(t);
                // LOG(INFO) << ip << ":" << port << "say#" << buffer;
                // sendto(_fd,client.c_str(),client.size(),0,CONV(&peer),Len);
            }
        }
    }
    ~udp_server(){
        ::close(_fd);
    }
private:
    int _fd;
    unordered_map<string,int> _userset;
    route_t _route;
    delete_t _del;
    adduser_t _add;
    uint16_t _port;
};
